﻿using Ionic.Zip;
using SubtitleDownloader.Providers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SubtitleDownloader
{
	public partial class Form1 : Form
	{
		private bool _isDoubleClick;
		private int _activeConnections;
		private FormWindowState _lastWindowState;
		private System.Windows.Forms.Timer _timer;

		public Form1()
		{
			InitializeComponent();
			this.Load += Form1_Load;

			_activeConnections = 0;
		}

		private void Exit()
		{
			this.Close();
			this.Dispose();
		}

		private void StartTimer()
		{
			Log("Starting timer...");
			if (_timer == null)
				_timer = new System.Windows.Forms.Timer();
			_timer.Interval = Data.Instance.UpdateInterval * 60 * 1000;
			_timer.Tick += (s, e) => SearchSubtitles();
			_timer.Start();
			Log("Timer started.");
		}

		private void StopTimer()
		{
			Log("Stopping timer...");
			if (_timer != null)
				_timer.Stop();
			Log("Timer stopped.");
		}

		private void Log(string message)
		{
			rtbLog.Invoke(() => {
				if (rtbLog.Lines.Length > 1000)
					rtbLog.Clear();
				rtbLog.AppendText(String.Format("{0}: {1}\n", DateTime.Now, message));
				rtbLog.ScrollToCaret();
			});
		}

		private List<SubtitleItem> GetSubtitles(VideoItem videoItem, ISubtitleProvider provider)
		{
			var ret = new List<SubtitleItem>();
			foreach (var sub in provider.GetSubtitles(videoItem)) {
				if (sub == null)
					continue;
				var rank = Utils.GetSimilarityIndex(sub.ExtraInfo, videoItem.ExtraInfo);
				if (rank == 100) {
					ret.Clear();
					ret.Add(sub);
					break;
				} else if (rank >= 75) {
					ret.Add(sub);
				}
			}
			return ret;
		}

		private void InitializeNotify()
		{
			_lastWindowState = FormWindowState.Normal;
			this.Resize += (s, e) => {
				if (this.WindowState != FormWindowState.Minimized)
					_lastWindowState = this.WindowState;
			};
			this.FormClosing += (s, e) => {
				this.Hide();
				e.Cancel = true;
			};
			ntfyIcon.MouseDoubleClick += (s, e) => {
				this.Show();
				this.WindowState = _lastWindowState;
				_isDoubleClick = true;
			};
			ntfyIcon.MouseClick += (s, e) => {
				if (e.Button == System.Windows.Forms.MouseButtons.Left) {
					Thread.Sleep(150);
					Application.DoEvents();
					//if (!_isDoubleClick)
					// One click action
					_isDoubleClick = false;
				}
			};
			ContextMenu menu = new ContextMenu();
			menu.MenuItems.Add("Exit", new EventHandler((s, e) => Exit()));
			ntfyIcon.ContextMenu = menu;
		}

		private void SearchSubtitles()
		{
			if (_activeConnections > 0)	// Search already in progress
				return;

			StopTimer();

			var activeDownloaders = 0;
			var searchSubtitles = new Action<string>(SearchSubtitles);
			foreach (var folder in Data.Instance.WatchedSeriesFolders) {
				activeDownloaders++;
				searchSubtitles.BeginInvoke(folder, (iar) => activeDownloaders--, null);
			}
			new Action(() => {
				while (_activeConnections > 0 || activeDownloaders > 0)
					Thread.Sleep(500);
				Log("Subtitle search process completed.");
				StartTimer();
			}).BeginInvoke(null, null);
		}

		private void SearchSubtitles(string folder)
		{
			if (folder == null)
				return;

			Log("Processing folder: " + folder);
			if (!Directory.Exists(folder)) {
				Log("Folder not exist: " + folder);
				return;
			}

			var activeConnections = 0;

			Log("Processing video items for " + folder);
			foreach (var videoItem in Utils.GetVideoItems(folder)) {
				while (_activeConnections >= Data.Instance.MaxSimConnections) {
					Thread.Sleep(100);
					Application.DoEvents();
				}
				activeConnections++;
				_activeConnections++;
				new Action(() => {
					foreach (var provider in Data.Instance.SubtitlesProviders) {
						Log("Processing " + videoItem.OriginalName + ", provider: " + provider.Name);
						var subtitles = GetSubtitles(videoItem, provider);
						if (subtitles.Count > 0) {
							Log(videoItem.OriginalName + ": Downloading subtitles.");
							var file = Utils.DownloadFile(subtitles[0].Url);
							if (file != null) {
								var extracted = Utils.Extract(file);
								if (extracted != null) {
									try {
										File.Copy(extracted, Path.ChangeExtension(videoItem.FileName, Path.GetExtension(extracted)), true);
										File.Delete(extracted);
										Log(videoItem.OriginalName + ": Subtitles downloaded.");
										break;
									} catch {
										Log(videoItem.OriginalName + ": Error while copying subtitle file.");
									}
								} else {
									Log(videoItem.OriginalName + ": Extraction error.");
								}
							} else {
								Log(videoItem.OriginalName + ": Download error.");
							}
						} else {
							Log(videoItem.OriginalName + ": No subtitles found.");
						}
					}
				}).BeginInvoke((iar) => { activeConnections--; _activeConnections--; }, null);
			}

			while (activeConnections > 0)
				Thread.Sleep(100);

			Log("Process completed for: " + folder);
		}

		#region Events

		void Form1_Load(object sender, EventArgs e)
		{
			Log("Program loaded, initializing UI...");
			InitializeNotify();
			StartTimer();
			Log("Ready.");
		}

		private void tsBtnSearchSubtitles_Click(object sender, EventArgs e)
		{
			SearchSubtitles();
		}

		private void tsBtnProgramSettings_Click(object sender, EventArgs e)
		{
			var frm = new ProgramSettings();
			if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
				Log("Settings saved.");
				if (frm.IntervalChanged) {
					Log("Scan interval changed, restarting timer...");
					StopTimer();
					StartTimer();
					Log("Timer restarted.");
				}
			}
		}

		#endregion
	}
}
